<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>伦敦金交易日记本</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
    <style>
        /* 自定义一些基础样式 */
        body {
            font-family: 'Inter', sans-serif; /* 使用 Inter 字体 */
            background-color: #f3f4f6; /* bg-gray-100 */
            padding: 1rem; /* p-4 */
        }
        @media (min-width: 768px) { /* md:p-8 */
            body {
                padding: 2rem;
            }
        }

        /* 改善数字输入框的外观 */
        input[type=number]::-webkit-inner-spin-button,
        input[type=number]::-webkit-calendar-picker-indicator {
            -webkit-appearance: none;
            margin: 0;
        }
        input[type=number] {
            -moz-appearance: textfield;
        }

        /* 页面容器基础样式 */
        .page-container {
            display: none; /* 初始隐藏所有页面 */
        }

        /* 加载状态 */
        .loading {
            display: none; /* 初始隐藏 */
            text-align: center;
            padding: 20px;
            color: #6b7280; /* text-gray-500 */
        }

        /* 错误消息样式 */
        .error-message {
            color: red;
            font-size: 0.875rem; /* text-sm */
            margin-top: 0.25rem; /* mt-1 */
        }

        /* 成功消息样式 */
        .success-message {
             color: green;
             font-size: 0.875rem; /* text-sm */
             margin-top: 0.25rem; /* mt-1 */
        }

        /* 卡片悬停效果 */
        .card-hover:hover {
             transform: translateY(-3px);
             box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); /* shadow-lg */
        }

        /* --- Styles for Native Date Input --- */
         /* Attempt to hide the native calendar icon/arrow */
        input[type="date"]::-webkit-calendar-picker-indicator {
            display: none;
        }
         /* Adjust padding to potentially prevent text cutoff near where the icon would be */
         input[type="date"] {
            padding-right: 1rem; /* Increased right padding */
            /* Font size reduced further */
            font-size: 0.75rem; /* text-xs */
         }
         /* Note: Hiding the native calendar icon might not work consistently across all Android WebView versions. */

        /* Style for active filter button */
        .filter-button.active {
            background-color: #f59e0b; /* bg-yellow-500 */
            color: white;
        }

        /* Style for notes summary in list */
        .notes-summary {
            display: -webkit-box;
            -webkit-line-clamp: 2; /* Limit to 2 lines */
            -webkit-box-orient: vertical;
            overflow: hidden;
            text-overflow: ellipsis;
            font-size: 0.875rem; /* text-sm */
            color: #4b5563; /* text-gray-600 */
            margin-top: 0.5rem; /* mt-2 */
        }

        /* Style for pinned entries in the list */
        .journal-entry.pinned {
            border-left: 4px solid #f59e0b; /* Highlight pinned entries */
        }

        /* Chart container styles */
        #priceChartContainer {
            width: 100%;
            height: 400px; /* Adjust height as needed */
            margin-top: 1.5rem; /* mt-6 */
            background-color: #ffffff; /* bg-white */
            border-radius: 0.5rem; /* rounded-lg */
            box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); /* shadow-md */
            padding: 1rem; /* p-4 */
            overflow-x: auto; /* Enable horizontal scrolling if chart is wider than container */
        }

         /* Style for the SVG element within the chart container */
         #priceChartContainer svg {
             display: block; /* Remove extra space below the svg */
         }

        /* Basic tooltip styles */
        .tooltip {
            position: absolute;
            text-align: center;
            padding: 8px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            border-radius: 4px;
            pointer-events: none; /* Allows mouse events to pass through */
            font-size: 0.875rem; /* text-sm */
            z-index: 10; /* Ensure tooltip is above other elements */
        }


    </style>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body class="bg-gray-100 p-4 md:p-8">

<div class="container mx-auto max-w-4xl bg-white rounded-lg shadow-xl p-6 md:p-8">

    <h1 class="text-2xl md:text-3xl font-bold text-center text-yellow-600 mb-6">伦敦金交易日记本</h1>

    <button id="backButton" class="mb-4 px-4 py-2 bg-gray-300 text-gray-800 font-semibold rounded-md shadow hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-300 transition duration-150 ease-in-out" style="display: none;">
        &larr; 返回
    </button>

    <div id="homepage" class="page-container">
        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
            <div id="addEntryCard" class="card-hover cursor-pointer bg-yellow-500 text-white p-6 rounded-lg shadow-md flex flex-col items-center justify-center text-center transition duration-200 ease-in-out">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
                </svg>
                <h2 class="text-xl font-semibold">添加交易日记</h2>
                <p class="text-sm opacity-90">记录每日交易数据与心得</p>
            </div>
            <div id="statsCard" class="card-hover cursor-pointer bg-blue-500 text-white p-6 rounded-lg shadow-md flex flex-col items-center justify-center text-center transition duration-200 ease-in-out">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
                </svg>
                <h2 class="text-xl font-semibold">查看统计分析</h2>
                <p class="text-sm opacity-90">回顾历史数据与表现</p>
            </div>
            <div id="backupCard" class="card-hover cursor-pointer bg-purple-500 text-white p-6 rounded-lg shadow-md flex flex-col items-center justify-center text-center transition duration-200 ease-in-out md:col-span-2">
                <svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-2 4l4 4m0 0l4-4m-4 4V4" />
                </svg>
                <h2 class="text-xl font-semibold">数据备份与恢复</h2>
                <p class="text-sm opacity-90">导出或导入交易记录数据</p>
            </div>
        </div>
    </div>

    <div id="addEntryPage" class="page-container">
        <h2 id="addEditPageTitle" class="text-xl font-semibold mb-4 text-gray-700">添加新记录</h2>
        <div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
            <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
                <div>
                    <label for="date" class="block text-sm font-medium text-gray-700 mb-1">日期:</label>
                    <input type="date" id="date" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500" required>
                    <p id="date-error" class="error-message"></p>
                </div>
                <div class="col-span-2 md:col-span-3"> <label for="title" class="block text-sm font-medium text-gray-700 mb-1">标题 (可选):</label>
                    <input type="text" id="title" placeholder="例如 今日交易总结" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500">
                    <p id="title-error" class="error-message"></p>
                </div>
                <div>
                    <label for="open" class="block text-sm font-medium text-gray-700 mb-1">开盘价 (可选):</label>
                    <input type="number" step="0.01" id="open" placeholder="例如 1850.50" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500">
                    <p id="open-error" class="error-message"></p>
                </div>
                <div>
                    <label for="close" class="block text-sm font-medium text-gray-700 mb-1">收盘价 (可选):</label>
                    <input type="number" step="0.01" id="close" placeholder="例如 1865.20" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500">
                    <p id="close-error" class="error-message"></p>
                </div>
                <div>
                    <label for="high" class="block text-sm font-medium text-gray-700 mb-1">最高价 (可选):</label>
                    <input type="number" step="0.01" id="high" placeholder="例如 1870.00" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500">
                    <p id="high-error" class="error-message"></p>
                </div>
                <div>
                    <label for="low" class="block text-sm font-medium text-gray-700 mb-1">最低价 (可选):</label>
                    <input type="number" step="0.01" id="low" placeholder="例如 1845.80" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500">
                    <p id="low-error" class="error-message"></p>
                </div>
            </div>
            <p id="price-logic-error" class="error-message mb-4"></p>

            <div class="mb-4">
                <label for="notes" class="block text-sm font-medium text-gray-700 mb-1">交易心得 (可选):</label>
                <textarea id="notes" rows="6" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-yellow-500 focus:border-yellow-500" placeholder="记录今天的交易想法、策略、情绪等..."></textarea>
            </div>

            <button id="addEntryBtn" class="w-full md:w-auto px-6 py-2 bg-yellow-500 text-white font-semibold rounded-md shadow hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 transition duration-150 ease-in-out">
                添加记录
            </button>
            <p id="add-success-message" class="success-message mt-2" style="display: none;">记录添加成功!</p>
        </div>
    </div>

    <div id="statsListPage" class="page-container">
        <h2 class="text-xl font-semibold mb-4 text-gray-700">交易记录列表</h2>
        <div class="mb-6 p-6 bg-gray-50 rounded-lg border border-gray-200">
            <h3 class="text-lg font-semibold mb-3 text-gray-700">筛选与统计</h3>
            <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4 items-end">
                <div>
                    <label for="startDate" class="block text-sm font-medium text-gray-700 mb-1">开始日期:</label>
                    <input type="date" id="startDate" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
                </div>
                <div>
                    <label for="endDate" class="block text-sm font-medium text-gray-700 mb-1">结束日期:</label>
                    <input type="date" id="endDate" class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500">
                </div>
                <div class="flex space-x-2">
                    <button id="filterBtn" class="flex-1 px-4 py-2 bg-blue-500 text-white font-semibold rounded-md shadow hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out">
                        筛选并统计
                    </button>
                    <button id="resetBtn" class="flex-1 px-4 py-2 bg-gray-500 text-white font-semibold rounded-md shadow hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 transition duration-150 ease-in-out">
                        重置筛选
                    </button>
                </div>
            </div>
            <div class="flex space-x-2 mb-4">
                <button id="filterAllBtn" class="filter-button flex-1 px-4 py-2 bg-gray-300 text-gray-800 font-semibold rounded-md shadow hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-300 transition duration-150 ease-in-out active" data-filter="all">
                    全部
                </button>
                <button id="filterPriceBtn" class="filter-button flex-1 px-4 py-2 bg-gray-300 text-gray-800 font-semibold rounded-md shadow hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-300 transition duration-150 ease-in-out" data-filter="price">
                    价格
                </button>
                <button id="filterNotesBtn" class="filter-button flex-1 px-4 py-2 bg-gray-300 text-gray-800 font-semibold rounded-md shadow hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-300 transition duration-150 ease-in-out" data-filter="notes">
                    心得
                </button>
            </div>
            <p id="filter-error" class="error-message mb-4"></p>
            <div id="statsDisplay" class="mt-4 p-4 bg-yellow-50 rounded-md border border-yellow-200 grid grid-cols-2 md:grid-cols-4 gap-4 text-center" style="display: none;">
                <div>
                    <p class="text-sm font-medium text-gray-600">区间最高价</p>
                    <p id="statHighest" class="text-lg font-bold text-red-600">-</p>
                </div>
                <div>
                    <p class="text-sm font-medium text-gray-600">区间最低价</p>
                    <p id="statLowest" class="text-lg font-bold text-green-600">-</p>
                </div>
                <div>
                    <p class="text-sm font-medium text-gray-600">最大单日波幅</p>
                    <p id="statMaxRange" class="text-lg font-bold text-blue-600">-</p>
                </div>
                <div>
                    <p class="text-sm font-medium text-gray-600">平均单日波幅</p>
                    <p id="statAvgRange" class="text-lg font-bold text-purple-600">-</p>
                </div>
            </div>
            <div class="mt-6 text-center">
                <button id="showChartBtn" class="px-6 py-2 bg-green-500 text-white font-semibold rounded-md shadow hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition duration-150 ease-in-out">
                    查看价格图表
                </button>
            </div>
        </div>

        <div class="loading" id="loadingIndicator">加载中...</div>
        <div id="journalList" class="grid grid-cols-1 md:grid-cols-3 gap-4">
        </div>
        <p id="no-data-message" class="text-center text-gray-500 py-4" style="display: none;">暂无记录或筛选结果为空。</p>
    </div>

    <div id="detailPage" class="page-container">
        <h2 class="text-xl font-semibold mb-4 text-gray-700">交易记录详情</h2>
        <div id="detailContent" class="p-6 bg-gray-50 rounded-lg border border-gray-200">
            <div class="flex justify-between items-center mb-4 border-b pb-2 border-gray-200">
                <h3 id="detailDate" class="text-lg font-semibold text-gray-800">-</h3>
                <div class="flex space-x-2">
                    <button id="pinDetailEntryBtn" class="text-sm text-gray-600 hover:text-gray-800">
                        <span id="pinButtonText">置顶</span>
                    </button>
                    <button id="editDetailEntryBtn" class="text-sm text-blue-500 hover:text-blue-700">修改</button>
                    <button id="deleteDetailEntryBtn" class="text-sm text-red-500 hover:text-red-700">删除记录</button>
                </div>
            </div>
            <div id="detailPriceContainer" style="display: none;">
                <div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm text-center mb-4">
                    <div class="bg-blue-50 p-2 rounded">
                        <p class="text-xs text-blue-500 font-medium">开盘</p>
                        <p id="detailOpen" class="font-semibold text-blue-700">-</p>
                    </div>
                    <div class="bg-green-50 p-2 rounded">
                        <p class="text-xs text-green-500 font-medium">收盘</p>
                        <p id="detailClose" class="font-semibold text-green-700">${formatPrice(entry.close)}</p>
                    </div>
                    <div class="bg-red-50 p-2 rounded">
                        <p class="text-xs text-red-500 font-medium">最高</p>
                        <p id="detailHigh" class="font-semibold text-red-700">${formatPrice(entry.high)}</p>
                    </div>
                    <div class="bg-yellow-50 p-2 rounded">
                        <p class="text-xs text-yellow-500 font-medium">最低</p>
                        <p id="detailLow" class="font-semibold text-yellow-700">${formatPrice(entry.low)}</p>
                    </div>
                </div>
                <div class="mb-4 p-3 bg-gray-100 rounded-md">
                    <p class="text-sm font-medium text-gray-700 mb-1">波幅:</p>
                    <p id="detailRange" class="text-md font-bold text-gray-800">-</p>
                </div>
            </div>
            <div class="mb-4" id="detailTitleContainer" style="display: none;">
                <p class="text-sm font-medium text-gray-700 mb-1">标题:</p>
                <p id="detailTitle" class="text-md font-bold text-gray-800">-</p>
            </div>
            <div> <p class="text-sm font-medium text-gray-700 mb-1">交易心得:</p>
                <p id="detailNotes" class="text-gray-600 leading-relaxed">-</p>
            </div>
        </div>
    </div>

    <div id="chartPage" class="page-container">
        <h2 class="text-xl font-semibold mb-4 text-gray-700">价格走势图</h2>
        <div id="chartInfo" class="mb-4 text-sm text-gray-600"></div>
        <div id="priceChartContainer">
        </div>
        <p id="no-chart-data-message" class="text-center text-gray-500 py-4" style="display: none;">所选时间范围内没有足够的有效价格数据来绘制图表。</p>
    </div>


    <div id="backupPage" class="page-container">
        <h2 class="text-xl font-semibold mb-4 text-gray-700">数据备份与恢复</h2>
        <div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200 text-center">
            <p class="text-gray-700 mb-6">您可以将交易记录导出到文件进行备份，或从文件导入数据进行恢复。</p>
            <div class="flex flex-col md:flex-row space-y-4 md:space-y-0 md:space-x-4 justify-center">
                <button id="exportDataBtn" class="px-6 py-2 bg-green-500 text-white font-semibold rounded-md shadow hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 transition duration-150 ease-in-out">
                    导出数据
                </button>
                <button id="importDataBtn" class="px-6 py-2 bg-blue-500 text-white font-semibold rounded-md shadow hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150 ease-in-out">
                    导入数据
                </button>
            </div>
            <p id="backup-message" class="success-message mt-4" style="display: none;"></p>
            <p id="backup-error" class="error-message mt-4" style="display: none;"></p>
        </div>
    </div>


</div>

<script>
        // --- DOM Elements ---
        const homepage = document.getElementById('homepage');
        const addEntryPage = document.getElementById('addEntryPage');
        const statsListPage = document.getElementById('statsListPage');
        const detailPage = document.getElementById('detailPage');
        const chartPage = document.getElementById('chartPage'); // New chart page element
        const backupPage = document.getElementById('backupPage'); // New backup page element
        const backButton = document.getElementById('backButton');

        const addEntryCard = document.getElementById('addEntryCard');
        const statsCard = document.getElementById('statsCard');
        const backupCard = document.getElementById('backupCard'); // New backup card element

        // Add/Edit Entry Page Elements
        const addEditPageTitle = document.getElementById('addEditPageTitle'); // Title for Add/Edit page
        const dateInput = document.getElementById('date');
        const titleInput = document.getElementById('title'); // New title input
        const notesInput = document.getElementById('notes');
        const openInput = document.getElementById('open');
        const closeInput = document.getElementById('close');
        const highInput = document.getElementById('high');
        const lowInput = document.getElementById('low');
        const addEntryBtn = document.getElementById('addEntryBtn'); // This button will be used for Add and Save Edit
        const addSuccessMessage = document.getElementById('add-success-message');

        // Stats List Page Elements
        const journalList = document.getElementById('journalList');
        const startDateInput = document.getElementById('startDate');
        const endDateInput = document.getElementById('endDate');
        const filterBtn = document.getElementById('filterBtn'); // Date range filter button
        const resetBtn = document.getElementById('resetBtn'); // Date range reset button
        const filterAllBtn = document.getElementById('filterAllBtn'); // Filter button: All
        const filterPriceBtn = document.getElementById('filterPriceBtn'); // Filter button: Price
        const filterNotesBtn = document.getElementById('filterNotesBtn'); // Filter button: Notes
        const filterButtons = document.querySelectorAll('.filter-button'); // All filter buttons
        const statsDisplay = document.getElementById('statsDisplay');
        const statHighest = document.getElementById('statHighest');
        const statLowest = document.getElementById('statLowest');
        const statMaxRange = document.getElementById('statMaxRange');
        const statAvgRange = document.getElementById('statAvgRange');
        const showChartBtn = document.getElementById('showChartBtn'); // New chart button
        const loadingIndicator = document.getElementById('loadingIndicator');
        const noDataMessage = document.getElementById('no-data-message');

        // Detail Page Elements
        const detailContent = document.getElementById('detailContent');
        const detailDate = document.getElementById('detailDate');
        const detailTitleContainer = document.getElementById('detailTitleContainer'); // Container for detail title
        const detailTitle = document.getElementById('detailTitle'); // Detail title
        const detailPriceContainer = document.getElementById('detailPriceContainer'); // Container for detail price info
        const detailOpen = document.getElementById('detailOpen');
        const detailClose = document.getElementById('detailClose');
        const detailHigh = document.getElementById('detailHigh');
        const detailLow = document.getElementById('detailLow');
        const detailRange = document.getElementById('detailRange');
        const detailNotes = document.getElementById('detailNotes');
        const pinDetailEntryBtn = document.getElementById('pinDetailEntryBtn'); // 置顶按钮
        const pinButtonText = document.getElementById('pinButtonText'); // 置顶按钮文本
        const editDetailEntryBtn = document.getElementById('editDetailEntryBtn'); // Edit button on detail page
        const deleteDetailEntryBtn = document.getElementById('deleteDetailEntryBtn'); // Delete button on detail page

        // Chart Page Elements
        const priceChartContainer = document.getElementById('priceChartContainer'); // Chart container
        const chartInfo = document.getElementById('chartInfo'); // Chart info display
        const noChartDataMessage = document.getElementById('no-chart-data-message'); // No chart data message


        // Backup Page Elements
        const exportDataBtn = document.getElementById('exportDataBtn'); // 导出按钮
        const importDataBtn = document.getElementById('importDataBtn'); // 导入按钮
        const backupMessage = document.getElementById('backup-message'); // 备份消息显示
        const backupError = document.getElementById('backup-error'); // 备份错误显示


        // --- Error Message Elements ---
        const dateError = document.getElementById('date-error');
        const titleError = document.getElementById('title-error'); // New title error element
        const openError = document.getElementById('open-error');
        const closeError = document.getElementById('close-error');
        const highError = document.getElementById('high-error');
        const lowError = document.getElementById('low-error');
        const priceLogicError = document.getElementById('price-logic-error');
        const filterError = document.getElementById('filter-error');


        const JOURNAL_STORAGE_KEY = 'londonGoldJournalEntries';
        let currentView = 'homepage'; // Track current page view
        let editingDate = null; // Track the date of the entry being edited (null when adding)
        let currentFilter = 'all'; // Track the current filter ('all', 'price', 'notes')
        let currentFilteredEntries = []; // Store the currently filtered entries for chart


        // --- Navigation Functions ---

        /**
         * 显示指定的页面并隐藏其他页面
         * 同时更新浏览器历史状态，支持手机返回键
         * @param {string} pageId - 要显示的页面ID ('homepage', 'addEntryPage', 'statsListPage', 'detailPage', 'chartPage', 'backupPage')
         * @param {boolean} [pushState=true] - 是否将当前页面状态推送到历史记录 (默认为 true)
         */
        function showPage(pageId, pushState = true) {
            console.log(`showPage called with pageId: ${pageId}, pushState: ${pushState}`); // Log showPage calls
            // 隐藏所有页面容器
            homepage.style.display = 'none';
            addEntryPage.style.display = 'none';
            statsListPage.style.display = 'none';
            detailPage.style.display = 'none';
            chartPage.style.display = 'none'; // Hide chart page
            backupPage.style.display = 'none'; // Hide backup page
            backButton.style.display = 'none'; // 默认隐藏返回按钮

            // 清除备份相关的消息
            if (backupMessage) backupMessage.style.display = 'none';
            if (backupError) backupError.style.display = 'none';


            switch (pageId) {
                case 'homepage':
                    console.log("Switching to homepage.");
                    // 显示首页
                    if (homepage) { // Add check
                        homepage.style.display = 'block';
                        console.log("Homepage display set to block.");
                    } else {
                        console.error("Homepage element not found!");
                    }
                    // 确保编辑状态在返回首页时重置
                    editingDate = null;
                    break;
                case 'addEntryPage':
                    console.log("Switching to addEntryPage.");
                    // 显示添加/修改页面
                    if (addEntryPage) addEntryPage.style.display = 'block'; else console.error("addEntryPage element not found!"); // Add check
                    if (backButton) backButton.style.display = 'block'; else console.error("backButton element not found!"); // 显示返回按钮 // Add check
                    clearErrors(); // 进入添加/修改页面时清除错误消息

                    if (editingDate) {
                        // 如果 editingDate 有值，说明是修改现有记录模式
                        if (addEditPageTitle) addEditPageTitle.textContent = '修改记录'; else console.error("addEditPageTitle element not found!"); // Add check
                        if (addEntryBtn) addEntryBtn.textContent = '保存修改'; else console.error("addEntryBtn element not found!"); // Add check
                        if (dateInput) dateInput.disabled = true; else console.error("dateInput element not found!"); // 修改模式下禁用日期输入框，不允许修改日期 // Add check

                        // 加载并填充要修改的记录数据到表单
                        const entries = loadEntries();
                        const entryToEdit = entries.find(entry => entry.date === editingDate);
                        if (entryToEdit) {
                            if (dateInput) dateInput.value = entryToEdit.date; // Add check
                            if (titleInput) titleInput.value = entryToEdit.title || ''; // Populate title // Add check
                            if (notesInput) notesInput.value = entryToEdit.notes || ''; // Add check
                            // 填充价格，如果为 0 则显示为空白
                            if (openInput) openInput.value = entryToEdit.open === 0 ? '' : entryToEdit.open; // Add check
                            if (closeInput) closeInput.value = entryToEdit.close === 0 ? '' : entryToEdit.close; // Add check
                            if (highInput) highInput.value = entryToEdit.high === 0 ? '' : entryToEdit.high; // Add check
                            if (lowInput) lowInput.value = entryToEdit.low === 0 ? '' : entryToEdit.low; // Add check
                        } else {
                            // 如果未找到要修改的记录，给出提示并返回列表页
                            alert('未找到要修改的记录。');
                            showPage('statsListPage');
                            editingDate = null; // 重置编辑状态
                        }

                    } else {
                        // 如果 editingDate 为 null，说明是添加新记录模式
                        if (addEditPageTitle) addEditPageTitle.textContent = '添加新记录'; // Add check
                        if (addEntryBtn) addEntryBtn.textContent = '添加记录'; // Add check
                        if (dateInput) dateInput.disabled = false; // 添加模式下启用日期输入框 // Add check

                        // 清空表单并设置默认日期为今天
                        if (notesInput) notesInput.value = ''; // Add check
                        if (titleInput) titleInput.value = ''; // Clear title input // Add check
                        if (openInput) openInput.value = ''; // Add check
                        if (closeInput) closeInput.value = ''; // Add check
                        if (highInput) highInput.value = ''; // Add check
                        if (lowInput) lowInput.value = ''; // Add check
                        const today = new Date();
                        const year = today.getFullYear();
                        const month = String(today.getMonth() + 1).padStart(2, '0');
                        const day = String(today.getDate()).padStart(2, '0');
                        if (dateInput) dateInput.value = `${year}-${month}-${day}`; // Add check
                    }
                    break;
                case 'statsListPage':
                    console.log("Switching to statsListPage.");
                    // 显示统计列表页面
                    if (statsListPage) statsListPage.style.display = 'block'; else console.error("statsListPage element not found!"); // Add check
                    if (backButton) backButton.style.display = 'block'; else console.error("backButton element not found!"); // 显示返回按钮 // Add check
                    filterAndDisplayEntries(); // 进入统计页面时加载并显示列表
                    // 确保编辑状态在进入列表页时重置
                    editingDate = null;
                    break;
                case 'detailPage':
                    console.log("Switching to detailPage.");
                    // 显示记录详情页面
                    if (detailPage) detailPage.style.display = 'block'; else console.error("detailPage element not found!"); // Add check
                    if (backButton) backButton.style.display = 'block'; else console.error("backButton element not found!"); // 显示返回按钮 // Add check
                    // 进入详情页时，editingDate 应该已经被设置为当前记录的日期
                    if (!editingDate) {
                         // 如果不知何故在没有 editingDate 的情况下进入了详情页，返回列表页
                         console.error("editingDate is null when trying to show detail page.");
                         showPage('statsListPage');
                         return;
                    }
                    // 显示存储在 editingDate 中的记录的详情
                    displayEntryDetail(editingDate);
                    break;
                case 'chartPage': // New chart page case
                     console.log("Switching to chartPage.");
                     if (chartPage) chartPage.style.display = 'block'; else console.error("chartPage element not found!"); // Show chart page
                     if (backButton) backButton.style.display = 'block'; // Show back button
                     renderPriceChart(currentFilteredEntries.filter(entry => hasPriceInfoForStats(entry))); // Render chart with filtered price data
                     break;
                case 'backupPage': // Backup page case
                    console.log("Switching to backupPage.");
                    if (backupPage) backupPage.style.display = 'block'; else console.error("backupPage element not found!"); // 显示备份页面
                    if (backButton) backButton.style.display = 'block'; // 显示返回按钮
                    break;
                default:
                    console.warn(`Unknown pageId: ${pageId}. Showing homepage.`);
                    showPage('homepage', false); // Fallback to homepage
                    break;
            }
            currentView = pageId; // 更新当前视图状态
            console.log("Current view updated to:", currentView);

            // 更新浏览器历史状态，支持手机返回键
            if (pushState) {
                 // 避免在页面加载时的初始状态重复push
                 if (history.state === null || history.state.pageId !== pageId) {
                     history.pushState({ pageId: pageId }, '', '#' + pageId);
                     console.log("Pushed state:", { pageId: pageId });
                 } else {
                      console.log("State already matches, not pushing.");
                 }
            }
        }

        // --- Utility Functions ---

        /**
         * 从 localStorage 加载交易记录
         * @returns {Array} 交易记录数组
         */
        function loadEntries() {
            console.log("loadEntries called."); // Log loadEntries call
            const entriesJson = localStorage.getItem(JOURNAL_STORAGE_KEY);
            console.log("Raw data from localStorage:", entriesJson ? entriesJson.substring(0, 200) + '...' : 'null'); // Log raw data (first 200 chars)

            try {
                const entries = entriesJson ? JSON.parse(entriesJson) : [];
                console.log("Parsed entries array length:", entries.length); // Log parsed array length

                 // Ensure data structure is complete, add missing fields for old data
                const processedEntries = entries.map(entry => ({
                    date: entry.date || '',
                    title: entry.title || '', // Load title
                    notes: entry.notes || '',
                    // Parse price, default to 0 if empty string or invalid number
                    open: parseFloat(entry.open) || 0,
                    close: parseFloat(entry.close) || 0,
                    high: parseFloat(entry.high) || 0,
                    low: parseFloat(entry.low) || 0,
                    isPinned: entry.isPinned === true // Ensure isPinned is boolean, default to false
                }));
                 console.log("Processed entries length:", processedEntries.length); // Log processed array length
                 return processedEntries;

            } catch (e) {
                console.error("加载记录时出错:", e);
                // 尝试加载失败时不弹窗，只在控制台记录错误，并返回空数组
                // alert("加载记录时出错，可能数据已损坏。将重置记录。");
                // localStorage.removeItem(JOURNAL_STORAGE_KEY); // Clear corrupted data
                return []; // Return empty array on error
            }
        }

        /**
         * 将交易记录保存到 localStorage
         * @param {Array} entries - 要保存的交易记录数组
         */
        function saveEntries(entries) {
            console.log("saveEntries called with entries length:", entries.length); // Log saveEntries call
            try {
                // Sort pinned entries first, then sort by date descending
                entries.sort((a, b) => {
                    // Pinned entries come first
                    if (a.isPinned && !b.isPinned) return -1;
                    if (!a.isPinned && b.isPinned) return 1;
                    // If both are pinned or both are not pinned, sort by date descending
                    return new Date(b.date) - new Date(a.date);
                });

                const entriesJson = JSON.stringify(entries);
                console.log("Saving JSON to localStorage:", entriesJson.substring(0, 200) + '...'); // Log saved JSON (first 200 chars)
                localStorage.setItem(JOURNAL_STORAGE_KEY, entriesJson);
                console.log("Entries saved successfully."); // Log success
            } catch (e) {
                console.error("保存记录时出错:", e);
                // alert("保存记录时出错，请检查浏览器设置或联系技术支持。"); // Avoid alert in WebView unless necessary
                showTemporaryMessage(backupError, "保存记录时出错。", 5000, true); // Use temporary message
            }
        }

        /**
         * 计算单日波幅
         * @param {number} high - 最高价
         * @param {number} low - 最低价
         * @returns {number} 波幅
         */
        function calculateRange(high, low) {
            const highNum = parseFloat(high);
            const lowNum = parseFloat(low);
            // Only calculate range if both high and low are valid numbers
            if (isNaN(highNum) || isNaN(lowNum) || highNum < lowNum) {
                return 0; // Return 0 if data is invalid or illogical
            }
            return highNum - lowNum;
        }

        /**
         * 检查记录是否包含有效的价格信息，足以用于统计计算和“价格”筛选。
         * 要求所有四个价格字段都是有效数字且最高不低于最低，并且至少有一个价格字段不为 0。
         * @param {Object} entry - 交易记录对象
         * @returns {boolean} 是否包含有效价格信息
         */
        function hasPriceInfoForStats(entry) {
             const openNum = parseFloat(entry.open);
             const closeNum = parseFloat(entry.close);
             const highNum = parseFloat(entry.high);
             const lowNum = parseFloat(entry.low);

             // 检查是否所有四个价格都是有效数字且最高不低于最低
             const isValidPriceStructure = !isNaN(openNum) && !isNaN(closeNum) && !isNaN(highNum) && !isNaN(lowNum) && highNum >= lowNum;

             // 检查是否至少有一个价格字段不为 0
             const hasNonZeroPrice = openNum !== 0 || closeNum !== 0 || highNum !== 0 || lowNum !== 0;

             const result = isValidPriceStructure && hasNonZeroPrice;
             console.log(`hasPriceInfoForStats for date ${entry.date}: open=${openNum}, close=${closeNum}, high=${highNum}, low=${lowNum}, isValidStructure=${isValidPriceStructure}, hasNonZeroPrice=${hasNonZeroPrice}, result=${result}`); // Detailed log

             return result;
        }

         /**
          * 检查记录是否有任意价格数据被输入 (即存储值不为 0)
          * 这个函数用于在“全部”筛选下，决定列表项是否显示价格摘要。
          * @param {Object} entry - 交易记录对象
          * @returns {boolean} 是否有任意价格数据
          */
         function hasAnyPriceData(entry) {
             // Check if the parsed float value is not 0 for any price field
             const result = parseFloat(entry.open) !== 0 || parseFloat(entry.close) !== 0 || parseFloat(entry.high) !== 0 || parseFloat(entry.low) !== 0;
             console.log(`hasAnyPriceData for date ${entry.date}: open=${parseFloat(entry.open)}, close=${parseFloat(entry.close)}, high=${parseFloat(entry.high)}, low=${parseFloat(entry.low)}, result=${result}`); // Detailed log
             return result;
         }


        /**
         * 格式化价格显示（保留两位小数）
         * 如果价格为 0，则显示 '-'
         * @param {number|string} price - 价格
         * @returns {string} 格式化后的价格字符串
         */
        function formatPrice(price) {
            const num = parseFloat(price);
            // If invalid number or 0, display '-'
            return isNaN(num) || num === 0 ? '-' : num.toFixed(2);
        }

        /**
         * 清除所有错误消息
         */
        function clearErrors() {
            if (dateError) dateError.textContent = '';
            if (titleError) titleError.textContent = '';
            if (openError) openError.textContent = '';
            if (closeError) closeError.textContent = '';
            if (highError) highError.textContent = '';
            if (lowError) lowError.textContent = '';
            if (priceLogicError) priceLogicError.textContent = '';
            if (filterError) filterError.textContent = '';
        }

        /**
         * 验证输入数据
         * 允许价格和标题为空，但日期必须输入且不能晚于今天
         * @returns {boolean} 是否验证通过
         */
        function validateInputs() {
            clearErrors();
            let isValid = true;
            const today = new Date().toISOString().split('T')[0]; // Get today's date inbeginPath-MM-DD format

            const dateVal = dateInput.value;
            const openVal = parseFloat(openInput.value); // Can be NaN
            const closeVal = parseFloat(closeInput.value); // Can be NaN
            const highVal = parseFloat(highInput.value); // Can be NaN
            const lowVal = parseFloat(lowInput.value); // Can be NaN

            // Date must be entered and cannot be in the future
            if (!dateVal) {
                if (dateError) dateError.textContent = '请选择日期';
                isValid = false;
            } else if (dateVal > today) {
                if (dateError) dateError.textContent = '日期不能晚于今天';
                isValid = false;
            }

            // Price fields and title are optional, but if entered, validate numbers
            if (openInput.value !== '' && isNaN(openVal)) {
                if (openError) openError.textContent = '请输入有效的开盘价';
                isValid = false;
            }
             if (closeInput.value !== '' && isNaN(closeVal)) {
                if (closeError) closeError.textContent = '请输入有效的收盘价';
                isValid = false;
            }
             if (highInput.value !== '' && isNaN(highVal)) {
                if (highError) highError.textContent = '请输入有效的最高价';
                isValid = false;
            }
             if (lowInput.value !== '' && isNaN(lowVal)) {
                if (lowError) lowError.textContent = '请输入有效的最低价';
                isValid = false;
            }

            // Price logic validation only applies if all price fields are valid numbers
            const allPricesValid = openInput.value !== '' && closeInput.value !== '' && highInput.value !== '' && lowInput.value !== '' &&
                                   !isNaN(openVal) && !isNaN(closeVal) && !isNaN(highVal) && !isNaN(lowVal);

            if (allPricesValid) {
                 if (highVal < lowVal) {
                     if (priceLogicError) priceLogicError.textContent = '最高价不能低于最低价';
                     isValid = false;
                 }
                 if (highVal < openVal) {
                      if (priceLogicError) priceLogicError.textContent = '最高价不能低于开盘价';
                      isValid = false;
                 }
                 if (highVal < closeVal) {
                      if (priceLogicError) priceLogicError.textContent = '最高价不能低于收盘价';
                      isValid = false;
                 }
                 if (lowVal > openVal) {
                      if (priceLogicError) priceLogicError.textContent = '最低价不能高于开盘价';
                      isValid = false;
                 }
                 if (lowVal > closeVal) {
                      if (priceLogicError) priceLogicError.textContent = '最低价不能高于收盘价';
                      isValid = false;
                 }
            } else if ((highInput.value !== '' && lowInput.value === '') || (highInput.value === '' && lowInput.value !== '')) {
                 // If only one of high/low is entered (and is valid), prompt for the other
                 if ((highInput.value !== '' && !isNaN(highVal)) || (lowInput.value !== '' && !isNaN(lowVal))) { // Check if the entered one is valid
                      if (priceLogicError) priceLogicError.textContent = '请输入有效的最高价和最低价以记录价格信息';
                      isValid = false;
                 }
            } else if (openInput.value !== '' || closeInput.value !== '' || highInput.value !== '' || lowInput.value !== '') {
                 // If any price field is entered but not all are valid numbers, show a general error
                 if (!allPricesValid) {
                      // Check if any price input has a value but is NaN after parseFloat
                      if ((openInput.value !== '' && isNaN(openVal)) ||
                          (closeInput.value !== '' && isNaN(closeVal)) ||
                          (highInput.value !== '' && isNaN(highVal)) ||
                          (lowInput.value !== '' && isNaN(lowVal))) {
                           // Individual errors will catch this, but if somehow missed:
                           // priceLogicError.textContent = '请检查输入的价格是否为有效数字';
                           // isValid = false;
                      } else if (openInput.value === '' || closeInput.value === '' || highInput.value === '' || lowInput.value === '') {
                           // If some price fields have values but others are empty
                           // priceLogicError.textContent = '请输入完整的价格信息或留空';
                           // isValid = false;
                      }
                 }
            }


            return isValid;
        }

        /**
         * 渲染交易记录列表 (统计页面只显示摘要卡片)
         * 根据当前筛选条件和记录内容决定显示格式
         * @param {Array} entries - 要渲染的交易记录数组
         */
        function renderEntriesList(entries) {
            console.log("renderEntriesList called with entries length:", entries.length); // Log render call
            if (journalList) journalList.innerHTML = ''; // Clear previous list // Add check
            if (noDataMessage) noDataMessage.style.display = 'none'; // Hide no data message by default // Add check

            // Filter entries based on currentFilter *before* rendering
            let filteredEntriesForDisplay = entries.filter(entry => {
                 // hasPriceInfoForStats 检查是否有完整的、非零的价格信息（用于价格筛选和统计）
                 const hasCompletePriceForStats = hasPriceInfoForStats(entry);
                 // hasAnyPriceData 检查是否有任意价格数据（用于在“全部”筛选下决定是否显示价格摘要）
                 const hasAnyPrice = hasAnyPriceData(entry);
                 // Consider title or notes as "notes info" for filtering
                 const hasNotesContent = entry.notes.trim() !== '' || entry.title.trim() !== '';

                 console.log(`Filtering entry ${entry.date} (Filter: ${currentFilter}): hasCompletePriceForStats=${hasCompletePriceForStats}, hasAnyPrice=${hasAnyPrice}, hasNotesContent=${hasNotesContent}`); // Log filtering decision factors


                 if (currentFilter === 'all') {
                     return true; // 显示所有记录
                 } else if (currentFilter === 'price') {
                     // 在“价格”筛选下，只显示有完整且非零价格信息的记录
                     const shouldInclude = hasCompletePriceForStats;
                     console.log(`Price filter: Including entry ${entry.date}? ${shouldInclude}`); // Log price filter decision
                     return shouldInclude;
                 } else if (currentFilter === 'notes') {
                     // 在“心得”筛选下，只显示有标题或心得内容的记录
                     const shouldInclude = hasNotesContent;
                     console.log(`Notes filter: Including entry ${entry.date}? ${shouldInclude}`); // Log notes filter decision
                     return shouldInclude;
                 }
                 return true; // 默认显示所有记录
            });

            console.log("Filtered entries for display length:", filteredEntriesForDisplay.length); // Log filtered length


            if (!filteredEntriesForDisplay || filteredEntriesForDisplay.length === 0) {
                if (noDataMessage) noDataMessage.style.display = 'block'; // Show no data message // Add check
                return;
            }

            filteredEntriesForDisplay.forEach(entry => {
                // 决定在列表项中是否显示价格摘要，使用 hasAnyPriceData
                const showPriceSummary = hasAnyPriceData(entry);
                const range = showPriceSummary ? calculateRange(entry.high, entry.low) : '-';

                const card = document.createElement('div');
                // 添加 'journal-entry' 类和 'pinned' 类
                card.className = `journal-entry card-hover cursor-pointer bg-white p-4 rounded-lg shadow border border-gray-200 flex flex-col justify-between transition duration-200 ease-in-out ${entry.isPinned ? 'pinned' : ''}`;
                card.setAttribute('data-date', entry.date); // Store date for detail page navigation

                let cardContent = `<h3 class="text-md font-semibold text-gray-800 mb-2">${entry.date}</h3>`;

                // Determine content based on filter and entry data
                if (currentFilter === 'price' || (currentFilter === 'all' && showPriceSummary)) {
                    // 如果是“价格”筛选，或者在“全部”筛选下且有任意价格数据，则显示价格详情
                    cardContent += `
                        <div class="grid grid-cols-2 gap-2 text-sm text-center">
                            <div class="bg-blue-50 p-1 rounded">
                                <p class="text-xs text-blue-500 font-medium">开盘</p>
                                <p class="font-semibold text-blue-700">${formatPrice(entry.open)}</p>
                            </div>
                            <div class="bg-green-50 p-1 rounded">
                                <p class="text-xs text-green-500 font-medium">收盘</p>
                                <p class="font-semibold text-green-700">${formatPrice(entry.close)}</p>
                            </div>
                            <div class="bg-red-50 p-1 rounded">
                                <p class="text-xs text-red-500 font-medium">最高</p>
                                <p class="font-semibold text-red-700">${formatPrice(entry.high)}</p>
                            </div>
                            <div class="bg-yellow-50 p-1 rounded">
                                <p class="text-xs text-yellow-500 font-medium">最低</p>
                                <p class="font-semibold text-yellow-700">${formatPrice(entry.low)}</p>
                            </div>
                        </div>
                        <div class="mt-3 text-center text-sm text-gray-600">
                             波幅: <span class="font-semibold">${typeof range === 'number' ? formatPrice(range) : range}</span>
                        </div>
                    `;
                }

                // 总是显示标题和心得摘要，除非是“价格”筛选
                if (currentFilter !== 'price') {
                     if (entry.title.trim() !== '') {
                         cardContent += `<h4 class="text-base font-medium text-gray-700 mt-2">${entry.title}</h4>`;
                     }
                     if (entry.notes.trim() !== '') {
                         cardContent += `<p class="notes-summary">${entry.notes}</p>`;
                     } else if (entry.title.trim() === '' && !showPriceSummary) { // 如果没有标题，没有心得，也没有价格摘要，则显示无内容
                         cardContent += `<p class="notes-summary text-gray-500">无内容记录</p>`;
                     }
                }


                card.innerHTML = cardContent;
                if (journalList) journalList.appendChild(card); // Add check

                // Add click listener for each card
                card.addEventListener('click', handleEntryCardClick);
            });
        }

        /**
         * Handle click event on an entry card, navigate to detail page.
         * @param {Event} event - The click event object.
         */
        function handleEntryCardClick(event) {
             // Find the closest parent element with the data-date attribute (the card itself)
             const cardElement = event.target.closest('.card-hover');
             if (!cardElement) return;

             const dateToView = cardElement.getAttribute('data-date');
             if (dateToView) {
                 editingDate = dateToView; // Set editingDate when viewing detail
                 showPage('detailPage');
             }
        }


        /**
         * 显示指定日期的记录详情
         * @param {string} date - 要显示的记录日期
         */
        function displayEntryDetail(date) {
            console.log("displayEntryDetail called for date:", date); // Log the date being displayed
            const entries = loadEntries();
            const entry = entries.find(entry => entry.date === date);

            if (entry) {
                console.log("Entry found:", entry); // Log the found entry object
                if (detailDate) detailDate.textContent = entry.date; else console.error("detailDate element not found!"); // Add check and log

                // Update pin button text and color based on pinned status
                if (pinDetailEntryBtn && pinButtonText) { // Check elements
                     pinDetailEntryBtn.setAttribute('data-date', entry.date); // Set data attribute for pin button
                     if (entry.isPinned) {
                         pinButtonText.textContent = '取消置顶';
                         pinDetailEntryBtn.classList.remove('text-gray-600', 'hover:text-gray-800');
                         pinDetailEntryBtn.classList.add('text-yellow-600', 'hover:text-yellow-800'); // Highlight pinned state
                     } else {
                         pinButtonText.textContent = '置顶';
                         pinDetailEntryBtn.classList.remove('text-yellow-600', 'hover:text-yellow-800');
                         pinDetailEntryBtn.classList.add('text-gray-600', 'hover:text-gray-800'); // Default state
                     }
                } else {
                     console.error("Pin button elements not found!"); // Log if elements are missing
                }


                // Display price details if any price data was entered
                if (detailPriceContainer) { // Check price container
                    const anyPriceDataEntered = hasAnyPriceData(entry);
                    console.log("Any price data entered:", anyPriceDataEntered);

                    if (anyPriceDataEntered) {
                        detailPriceContainer.style.display = 'block';
                        console.log("Price container displayed.");

                        // Use formatPrice which handles 0 values by displaying '-'
                        if (detailOpen) detailOpen.textContent = formatPrice(entry.open); else console.error("detailOpen element not found!"); // Add check and log
                        if (detailClose) detailClose.textContent = formatPrice(entry.close); else console.error("detailClose element not found!"); // Add check and log
                        if (detailHigh) detailHigh.textContent = formatPrice(entry.high); else console.error("detailHigh element not found!"); // Add check and log
                        if (detailLow) detailLow.textContent = formatPrice(entry.low); else console.error("detailLow element not found!"); // Add check and log
                        console.log("Prices attempted to display:", { open: entry.open, close: entry.close, high: entry.high, low: entry.low });

                        // Calculate and display range only if high and low are valid numbers
                        if (detailRange) { // Add check
                            const range = (!isNaN(parseFloat(entry.high)) && !isNaN(parseFloat(entry.low))) ? calculateRange(entry.high, entry.low) : '-';
                            detailRange.textContent = typeof range === 'number' ? formatPrice(range) : range;
                            console.log("Range calculated and displayed:", range);
                        } else {
                             console.error("Detail range element not found!"); // Log if range element is missing
                         }

                    } else {
                        detailPriceContainer.style.display = 'none';
                         // Reset price fields display to '-' when container is hidden
                         if (detailOpen) detailOpen.textContent = '-';
                         if (detailClose) detailClose.textContent = '-';
                         if (detailHigh) detailHigh.textContent = '-';
                         if (detailLow) detailLow.textContent = '-';
                         if (detailRange) detailRange.textContent = '-';
                         console.log("No price data entered, price container hidden.");
                    }
                } else {
                     console.error("Detail price container element not found!"); // Log if price container is missing
                }

                // Display title if available (moved below price)
                if (detailTitleContainer && detailTitle) { // Add checks
                    if (entry.title && entry.title.trim() !== '') {
                         detailTitleContainer.style.display = 'block';
                         detailTitle.textContent = entry.title;
                         console.log("Title displayed:", entry.title);
                    } else {
                         detailTitleContainer.style.display = 'none';
                         detailTitle.textContent = '-';
                         console.log("No title to display.");
                    }
                } else {
                     console.error("Detail title elements not found!"); // Log if title elements are missing
                }


                // Always display notes
                if (detailNotes) { // Add check
                    detailNotes.textContent = entry.notes || '无心得记录';
                    console.log("Notes displayed:", detailNotes.textContent);
                } else {
                     console.error("detailNotes element not found!"); // Log if notes element is missing
                }


                // Set data attributes for buttons
                if (deleteDetailEntryBtn) deleteDetailEntryBtn.setAttribute('data-date', entry.date); else console.error("deleteDetailEntryBtn element not found!"); // Add check and log
                if (editDetailEntryBtn) editDetailEntryBtn.setAttribute('data-date', entry.date); else console.error("editDetailEntryBtn element not found!"); // Add check and log


            } else {
                console.error("Entry not found for date:", date);
                alert('未找到该日期的记录。');
                showPage('statsListPage');
            }
             console.log("displayEntryDetail finished.");
        }

         /**
          * 处理详情页删除记录事件
          * @param {Event} event - 点击事件对象
          */
         function handleDeleteEntry(event) {
             const dateToDelete = event.target.getAttribute('data-date');
             if (!dateToDelete) return;

             if (confirm(`确定要删除日期为 ${dateToDelete} 的记录吗？`)) {
                 let entries = loadEntries();
                 entries = entries.filter(entry => entry.date !== dateToDelete);
                 saveEntries(entries);

                 showTemporaryMessage(addSuccessMessage, "记录删除成功!", 3000, false); // 使用绿色表示成功

                 // 删除后返回统计列表页并刷新
                 // *** 修改：先替换历史状态，然后使用 history.back() 返回 ***
                 // 替换当前的历史状态 (detailPage) 为 statsListPage
                 history.replaceState({ pageId: 'statsListPage' }, '', '#statsListPage');
                 console.log("Replaced state with:", { pageId: 'statsListPage' });

                 // 使用 history.back() 返回到新的栈顶状态 (statsListPage)
                 // 这会触发 onpopstate，onpopstate 会调用 showPage('statsListPage', false)
                 history.back();
                 console.log("Called history.back() after deleting.");

                 // Note: The showPage('statsListPage') call that was here is removed,
                 // as history.back() will trigger onpopstate which handles the rendering.

             }
         }

         /**
          * 处理点击详情页的修改按钮事件
          * @param {Event} event - 点击事件对象
          */
         function handleEditEntry(event) {
             const dateToEdit = event.target.getAttribute('data-date');
             if (dateToEdit) {
                 editingDate = dateToEdit; // 设置 editingDate，表示要修改这条记录
                 showPage('addEntryPage'); // 跳转到添加/修改表单页面
             }
         }

         /**
          * 处理点击详情页的置顶按钮事件
          * @param {Event} event - 点击事件对象
          */
         function handlePinEntry(event) {
             const dateToPin = event.target.closest('button').getAttribute('data-date'); // Use closest to get the button element
             if (!dateToPin) return;

             let entries = loadEntries();
             const entryIndex = entries.findIndex(entry => entry.date === dateToPin);

             if (entryIndex !== -1) {
                 const entry = entries[entryIndex];
                 entry.isPinned = !entry.isPinned; // Toggle pinned status
                 saveEntries(entries); // Save updated entries

                 // Update button text and color immediately
                 if (pinDetailEntryBtn && pinButtonText) {
                     if (entry.isPinned) {
                         pinButtonText.textContent = '取消置顶';
                         pinDetailEntryBtn.classList.remove('text-gray-600', 'hover:text-gray-800');
                         pinDetailEntryBtn.classList.add('text-yellow-600', 'hover:text-yellow-800');
                         showTemporaryMessage(backupMessage, `记录 ${dateToPin} 已置顶。`, 3000);
                     } else {
                         pinButtonText.textContent = '置顶';
                         pinDetailEntryBtn.classList.remove('text-yellow-600', 'hover:text-yellow-800');
                         pinDetailEntryBtn.classList.add('text-gray-600', 'hover:text-gray-800');
                         showTemporaryMessage(backupMessage, `记录 ${dateToPin} 已取消置顶。`, 3000);
                     }
                 }

                 // Optional: Navigate back to stats page to see the change immediately
                 // showPage('statsListPage');
             } else {
                 console.error("Entry not found for pinning:", dateToPin);
                 showTemporaryMessage(backupError, "置顶失败：未找到记录。", 3000, true);
             }
         }


        /**
         * 计算并显示统计数据
         * 只计算包含有效价格数据的记录
         * @param {Array} entries - 用于计算统计的交易记录数组
         */
        function calculateAndDisplayStats(entries) {
            console.log("calculateAndDisplayStats called with entries length:", entries.length); // Log stats call
            // Filter out entries with valid price data for stats calculation
            const priceEntries = entries.filter(entry => hasPriceInfoForStats(entry));

            console.log("Price entries for stats length:", priceEntries.length); // Log price entries length


            if (!priceEntries || priceEntries.length === 0) {
                if (statsDisplay) statsDisplay.style.display = 'none'; // Hide stats area if no valid price data // Add check
                // Reset stats display to '-'
                if (statHighest) statHighest.textContent = '-';
                if (statLowest) statLowest.textContent = '-';
                if (statMaxRange) statMaxRange.textContent = '-';
                if (statAvgRange) statAvgRange.textContent = '-';
                console.log("No price entries, stats display hidden."); // Log no price entries
                return;
            }

            let highest = -Infinity;
            let lowest = Infinity;
            let maxRange = 0;
            let totalRange = 0;
            let validEntriesCount = 0; // Count of entries with valid range for average calculation

            priceEntries.forEach(entry => {
                const high = parseFloat(entry.high);
                const low = parseFloat(entry.low);
                const range = calculateRange(high, low); // calculateRange already handles NaN/invalid logic

                if (high > highest) highest = high;
                if (low < lowest) lowest = low;

                if (!isNaN(range)) { // Only include valid ranges in total and count
                    if (range > maxRange) maxRange = range;
                    totalRange += range;
                    validEntriesCount++;
                }
            });

            const avgRange = validEntriesCount > 0 ? totalRange / validEntriesCount : 0;

            if (statHighest) statHighest.textContent = formatPrice(highest === -Infinity ? '-' : highest);
            if (statLowest) statLowest.textContent = formatPrice(lowest === Infinity ? '-' : lowest);
            if (statMaxRange) statMaxRange.textContent = formatPrice(maxRange);
            if (statAvgRange) statAvgRange.textContent = formatPrice(avgRange);

            if (statsDisplay) statsDisplay.style.display = 'grid'; // Show stats area // Add check
            console.log("Stats displayed: Highest:", statHighest.textContent, "Lowest:", statLowest.textContent, "Max Range:", statMaxRange.textContent, "Avg Range:", statAvgRange.textContent); // Log displayed stats
        }

        /**
         * 根据日期范围和当前筛选条件筛选记录并重新渲染列表和统计信息
         * 同时更新 currentFilteredEntries 供图表使用
         */
        function filterAndDisplayEntries() {
            console.log("filterAndDisplayEntries called."); // Log filter call
            if (loadingIndicator) loadingIndicator.style.display = 'block'; // Show loading indicator // Add check
            if (journalList) journalList.innerHTML = ''; // Clear list to show loading state // Add check
            if (statsDisplay) statsDisplay.style.display = 'none'; // Add check
            if (noDataMessage) noDataMessage.style.display = 'none'; // Add check
            if (showChartBtn) showChartBtn.style.display = 'none'; // Hide chart button initially // Add check
            clearErrors(); // Clear previous filter errors

            const startDate = startDateInput.value;
            const endDate = endDateInput.value;
            console.log("Filter dates: Start:", startDate, "End:", endDate); // Log filter dates


            // Validate date range
            if (startDate && endDate && startDate > endDate) {
                if (filterError) filterError.textContent = '开始日期不能晚于结束日期'; // Add check
                if (loadingIndicator) loadingIndicator.style.display = 'none'; // Hide loading indicator // Add check
                if (noDataMessage) noDataMessage.style.display = 'block'; // Show no data message (because filter is invalid) // Add check
                // Reset stats display to '-'
                if (statHighest) statHighest.textContent = '-';
                if (statLowest) statLowest.textContent = '-';
                if (statMaxRange) statMaxRange.textContent = '-';
                if (statAvgRange) statAvgRange.textContent = '-';
                console.warn("Invalid date range filter."); // Log invalid filter
                currentFilteredEntries = []; // Clear filtered entries on invalid filter
                return;
            }

            // Use setTimeout to simulate async loading effect and prevent UI blocking
            setTimeout(() => {
                const allEntries = loadEntries(); // loadEntries already sorts by pinned and then date
                let filteredEntries = allEntries;

                // Apply date range filter first
                if (startDate || endDate) {
                    filteredEntries = allEntries.filter(entry => {
                        const entryDate = entry.date;
                        const isAfterStart = startDate ? entryDate >= startDate : true;
                        const isBeforeEnd = endDate ? entryDate <= endDate : true;
                        return isAfterStart && isBeforeEnd;
                    });
                     console.log("Entries after date filter length:", filteredEntries.length); // Log date filtered length
                }

                // Store the date-filtered entries for chart use
                currentFilteredEntries = filteredEntries;

                // Note: Content filtering for display is handled in renderEntriesList now.
                // Stats are calculated based on date-filtered entries that have price info.

                renderEntriesList(currentFilteredEntries); // Render list with all date-filtered entries, display logic handles content filter
                calculateAndDisplayStats(currentFilteredEntries); // Calculate stats based on date-filtered entries (stats function handles price check)

                // Show chart button if there are entries with price info in the current filter
                const priceEntriesForChart = currentFilteredEntries.filter(entry => hasPriceInfoForStats(entry));
                 if (showChartBtn) { // Add check
                     if (priceEntriesForChart.length > 1) { // Need at least 2 points for a line chart
                         showChartBtn.style.display = 'inline-block'; // Show chart button
                     } else {
                         showChartBtn.style.display = 'none'; // Hide chart button if not enough data
                     }
                 }


                if (loadingIndicator) loadingIndicator.style.display = 'none'; // Hide loading indicator // Add check
                 console.log("filterAndDisplayEntries finished."); // Log finish
            }, 100); // Short delay to show loading state
        }

        /**
         * 渲染价格走势图
         * @param {Array} data - 包含有效价格信息的交易记录数组
         */
        function renderPriceChart(data) {
             console.log("renderPriceChart called with data length:", data.length); // Log chart render call

             // Clear previous chart
             if (priceChartContainer) priceChartContainer.innerHTML = ''; else { console.error("priceChartContainer not found!"); return; } // Add check

             if (noChartDataMessage) noChartDataMessage.style.display = 'none'; // Hide no chart data message by default // Add check
             if (chartInfo) chartInfo.textContent = ''; // Clear chart info // Add check


             if (!data || data.length < 2) {
                 if (noChartDataMessage) noChartDataMessage.style.display = 'block'; // Show no chart data message // Add check
                 console.log("Not enough data to render chart."); // Log insufficient data
                 return;
             }

             // Sort data by date ascending for chart
             data.sort((a, b) => new Date(a.date) - new Date(b.date));
             console.log("Data sorted for chart:", data); // Log sorted data


             // Set up chart dimensions
             const containerWidth = priceChartContainer.clientWidth;
             const containerHeight = priceChartContainer.clientHeight;
             // Adjusted bottom margin for horizontal labels
             const margin = { top: 40, right: 30, bottom: 60, left: 50 }; // Reduced bottom margin slightly
             // *** Modification: Increased minWidthPerPoint to ensure more space between ticks ***
             const minWidthPerPoint = 80; // Minimum pixels per data point (adjust as needed)
             const calculatedWidth = data.length * minWidthPerPoint;
             // Use the larger of the calculated width or the available container width
             const chartWidth = Math.max(containerWidth - margin.left - margin.right, calculatedWidth);
             const chartHeight = containerHeight - margin.top - margin.bottom;


             // Create SVG element
             const svg = d3.select("#priceChartContainer")
                 .append("svg")
                 // Set SVG width to the calculated chartWidth + margins
                 .attr("width", chartWidth + margin.left + margin.right)
                 .attr("height", containerHeight) // Keep SVG height to container height
                 .append("g")
                 .attr("transform", `translate(${margin.left},${margin.top})`);

             // Define scales
             const xScale = d3.scaleTime()
                 .domain(d3.extent(data, d => new Date(d.date)))
                 // Set xScale range to the calculated chartWidth
                 .range([0, chartWidth]);


             const yScale = d3.scaleLinear()
                 // Extend the y-axis domain slightly beyond min/max for better visualization
                 .domain([d3.min(data, d => d.low) * 0.99, d3.max(data, d => d.high) * 1.01])
                 .range([chartHeight, 0]);

             // Define axes
             const xAxis = d3.axisBottom(xScale)
                 .tickFormat(d3.timeFormat("%m-%d")) // Format date on x-axis
                 // *** Modification: Explicitly set tick values to data points ***
                 .tickValues(data.map(d => new Date(d.date))); // Force ticks at each data point date


             const yAxis = d3.axisLeft(yScale);

             // Add X axis
             svg.append("g")
                 .attr("transform", `translate(0,${chartHeight})`)
                 .call(xAxis)
                 // Remove rotation and adjust positioning for horizontal labels
                 .selectAll("text")
                 .style("text-anchor", "middle") // Center text below the tick mark
                 .attr("dx", "0em") // Reset horizontal adjustment
                 .attr("dy", "1em"); // Adjust vertical position to move text below axis


             // Add Y axis
             svg.append("g")
                 .call(yAxis);

             // Add Y axis label (Removed as per user request)
             /*
             svg.append("text")
                 .attr("transform", "rotate(-90)")
                 .attr("x", 0 - (chartHeight / 2)) // Use chartHeight
                 .attr("y", 0 - margin.left - 15)
                 .attr("dy", "1em")
                 .style("text-anchor", "middle")
                 .text("价格"); // Y轴标签
             */


             // Define line generators
             const highPriceLine = d3.line()
                 .x(d => xScale(new Date(d.date)))
                 .y(d => yScale(d.high));

             const lowPriceLine = d3.line()
                 .x(d => xScale(new Date(d.date)))
                 .y(d => yScale(d.low));

             // Draw the high price line
             svg.append("path")
                 .datum(data)
                 .attr("fill", "none")
                 .attr("stroke", "red")
                 .attr("stroke-width", 1.5)
                 .attr("d", highPriceLine);

             // Draw the low price line
             svg.append("path")
                 .datum(data)
                 .attr("fill", "none")
                 .attr("stroke", "blue")
                 .attr("stroke-width", 1.5)
                 .attr("d", lowPriceLine);

             // Add tooltips (optional but helpful)
             const tooltip = d3.select("body").append("div")
                 .attr("class", "tooltip")
                 .style("opacity", 0)
                 .style("position", "absolute"); // Ensure position is absolute for correct placement


             // Add circles for data points and add hover effects
             svg.selectAll(".dot-high")
                 .data(data)
                 .enter().append("circle")
                 .attr("class", "dot-high")
                 .attr("cx", d => xScale(new Date(d.date)))
                 .attr("cy", d => yScale(d.high))
                 .attr("r", 4)
                 .attr("fill", "red")
                 .on("mouseover", (event, d) => {
                     tooltip.transition()
                         .duration(200)
                         .style("opacity", .9);
                     tooltip.html(`日期: ${d.date}<br/>最高价: ${formatPrice(d.high)}`)
                         .style("left", (event.pageX + 10) + "px")
                         .style("top", (event.pageY - 20) + "px");
                 })
                 .on("mouseout", () => {
                     tooltip.transition()
                         .duration(500)
                         .style("opacity", 0);
                 });

             svg.selectAll(".dot-low")
                 .data(data)
                 .enter().append("circle")
                 .attr("class", "dot-low")
                 .attr("cx", d => xScale(new Date(d.date)))
                 .attr("cy", d => yScale(d.low))
                 .attr("r", 4)
                 .attr("fill", "blue")
                 .on("mouseover", (event, d) => {
                     tooltip.transition()
                         .duration(200)
                         .style("opacity", .9);
                     tooltip.html(`日期: ${d.date}<br/>最低价: ${formatPrice(d.low)}`)
                         .style("left", (event.pageX + 10) + "px")
                         .style("top", (event.pageY - 20) + "px");
                 })
                 .on("mouseout", () => {
                     tooltip.transition()
                         .duration(500)
                         .style("opacity", 0);
                 });

             // Add chart title
             svg.append("text")
                 .attr("x", (chartWidth / 2)) // Use chartWidth for centering title
                 // Adjusted y position to move title down
                 .attr("y", 0 - (margin.top / 2) + 10) // Add 10px offset
                 .attr("text-anchor", "middle")
                 .style("font-size", "16px")
                 .style("text-decoration", "underline")
                 .text("最高价与最低价走势图");

             // Display chart info (date range)
             if (chartInfo && data.length > 0) {
                 const firstDate = data[0].date;
                 const lastDate = data[data.length - 1].date;
                 chartInfo.textContent = `图表范围: ${firstDate} 至 ${lastDate}`;
             }


             console.log("Chart rendered successfully."); // Log chart render success
        }


        /**
         * 显示临时消息
         * @param {HTMLElement} element - 显示消息的元素
         * @param {string} message - 要显示的消息
         * @param {number} duration - 显示时长（毫秒）
         * @param {boolean} isError - 是否是错误消息 (影响颜色)
         */
        function showTemporaryMessage(element, message, duration = 3000, isError = false) {
            if (element) { // Add check
                element.textContent = message;
                element.style.color = isError ? 'red' : 'green'; // Set color based on whether it's an error
                element.style.display = 'block';
                setTimeout(() => {
                    element.style.display = 'none';
                }, duration);
            } else {
                 console.error("Temporary message element not found!"); // Log if element is missing
            }
        }

        /**
         * 设置当前筛选按钮的激活状态
         * @param {string} filterType - 激活的筛选类型 ('all', 'price', 'notes')
         */
        function setActiveFilterButton(filterType) {
            filterButtons.forEach(button => {
                 if (button.getAttribute('data-filter') === filterType) {
                     button.classList.add('active');
                 } else {
                     button.classList.remove('active');
                 }
            });
        }


        // --- Event Listeners ---

        // Homepage card click events
        if (addEntryCard) { // Add check
            addEntryCard.addEventListener('click', () => {
                 editingDate = null; // 确保添加新记录时编辑状态是关闭的
                 showPage('addEntryPage');
            });
        } else { console.error("addEntryCard element not found!"); }

        if (statsCard) { // Add check
            statsCard.addEventListener('click', () => showPage('statsListPage'));
        } else { console.error("statsCard element not found!"); }

        // 数据备份卡片点击事件
        if (backupCard) { // Add check
             backupCard.addEventListener('click', () => showPage('backupPage'));
        } else { console.error("backupCard element not found!"); }


        // 返回按钮点击事件 (使用浏览器历史返回)
        if (backButton) { // Add check
            backButton.addEventListener('click', () => {
                history.back(); // 使用浏览器历史记录返回上一页
            });
        } else { console.error("backButton element not found!"); }


        // 添加/保存修改按钮点击事件
        if (addEntryBtn) { // Add check
            addEntryBtn.addEventListener('click', () => {
                if (!validateInputs()) {
                    return; // 如果验证失败则不继续
                }

                // 获取表单数据，将空字符串或无效数字转换为 0
                const newEntry = {
                    date: dateInput.value,
                    title: titleInput.value.trim(), // Get title value
                    notes: notesInput.value.trim(),
                    open: parseFloat(openInput.value) || 0,
                    close: parseFloat(closeInput.value) || 0,
                    high: parseFloat(highInput.value) || 0,
                    low: parseFloat(lowInput.value) || 0,
                    isPinned: false // New entries are not pinned by default
                };

                let entries = loadEntries();

                if (editingDate) {
                    // --- 修改现有记录 ---
                    const existingIndex = entries.findIndex(entry => entry.date === editingDate);
                     if (existingIndex !== -1) {
                         // 更新现有记录的字段（日期不变）
                         entries[existingIndex].title = newEntry.title; // Update title
                         entries[existingIndex].notes = newEntry.notes;
                         entries[existingIndex].open = newEntry.open;
                         entries[existingIndex].close = newEntry.close;
                         entries[existingIndex].high = newEntry.high;
                         entries[existingIndex].low = newEntry.low;
                         // Note: isPinned status is NOT changed when editing other fields

                         saveEntries(entries);
                         showTemporaryMessage(addSuccessMessage, "记录修改成功!", 3000);

                         // 返回到更新后的详情页
                         // 注意：我们仍然停留在同一日期，所以 editingDate 仍然是正确的
                         showPage('detailPage');

                     } else {
                         // 如果 editingDate 无效，理论上不应该发生
                         alert('修改失败：未找到原记录。');
                         showPage('statsListPage'); // 返回列表页
                     }

                } else {
                    // --- 添加新记录 ---
                    // 检查是否存在完全重复的记录 (日期、价格、心得都相同)
                    const isExactDuplicate = entries.some(existingEntry =>
                        existingEntry.date === newEntry.date &&
                        existingEntry.open === newEntry.open &&
                        existingEntry.close === existingEntry.close &&
                        existingEntry.high === existingEntry.high &&
                        existingEntry.low === existingEntry.low &&
                        existingEntry.notes === newEntry.notes // 检查心得内容
                        // 注意：标题不参与重复判断
                    );

                    if (isExactDuplicate) {
                        // 如果存在完全重复的记录，给出提示，不添加
                        alert(`已存在与当前输入完全相同的记录 (日期、价格、心得)。`);
                        // 可以选择不清空表单，方便用户修改
                        // clearForm(); // 如果需要清空表单
                        return; // 停止添加操作
                    } else {
                        // 如果不存在完全重复的记录，则添加新记录
                        entries.push(newEntry);
                        saveEntries(entries);

                        // 清空表单（日期可以保留或清空，这里选择清空标题、价格和心得）
                        // dateInput.value = '';
                        if (titleInput) titleInput.value = ''; // Clear title // Add check
                        if (notesInput) notesInput.value = ''; // Add check
                        if (openInput) openInput.value = ''; // Add check
                        if (closeInput) closeInput.value = ''; // Add check
                        if (highInput) highInput.value = ''; // Add check
                        if (lowInput) lowInput.value = ''; // Add check

                        // 显示成功消息
                        showTemporaryMessage(addSuccessMessage, "记录添加成功!", 3000);

                        // 添加成功后，可以选择停留在当前页面或跳转到列表页
                        // showPage('statsListPage'); // 示例：添加后自动跳转到列表页
                    }
                }
            });
        } else { console.error("addEntryBtn element not found!"); }


        // 筛选按钮点击事件 (在统计列表页面)
        if (filterBtn) filterBtn.addEventListener('click', filterAndDisplayEntries); else console.error("filterBtn element not found!"); // Add check

        // 重置按钮点击事件 (在统计列表页面)
        if (resetBtn) { // Add check
            resetBtn.addEventListener('click', () => {
                if (startDateInput) startDateInput.value = ''; // Add check
                if (endDateInput) endDateInput.value = ''; // Add check
                clearErrors(); // 清除可能存在的筛选错误
                filterAndDisplayEntries(); // 重新显示所有记录和统计
            });
        } else { console.error("resetBtn element not found!"); }


        // Filter buttons click events
        filterButtons.forEach(button => {
            button.addEventListener('click', () => {
                currentFilter = button.getAttribute('data-filter');
                setActiveFilterButton(currentFilter); // Set active button class
                filterAndDisplayEntries(); // Re-filter and display based on new filter
            });
        });

        // Chart button click event (on stats list page)
        if (showChartBtn) { // Add check
            showChartBtn.addEventListener('click', () => {
                 showPage('chartPage'); // Navigate to chart page
            });
        } else { console.error("showChartBtn element not found!"); }


        // 详情页删除记录按钮点击事件
        if (deleteDetailEntryBtn) deleteDetailEntryBtn.addEventListener('click', handleDeleteEntry); else console.error("deleteDetailEntryBtn element not found!"); // Add check

        // 详情页修改记录按钮点击事件
        if (editDetailEntryBtn) editDetailEntryBtn.addEventListener('click', handleEditEntry); else console.error("editDetailEntryBtn element not found!"); // Add check

        // 详情页置顶记录按钮点击事件
         if (pinDetailEntryBtn) pinDetailEntryBtn.addEventListener('click', handlePinEntry); else console.error("pinDetailEntryBtn element not found!"); // Add check


        // 备份页面导入导出按钮事件
        if (exportDataBtn) { // Add check
             exportDataBtn.addEventListener('click', handleExportData);
        } else { console.error("exportDataBtn element not found!"); }

        if (importDataBtn) { // Add check
             importDataBtn.addEventListener('click', handleImportData);
        } else { console.error("importDataBtn element not found!"); }


        // --- 数据备份/恢复功能相关的 JavaScript ---

        // Define the JavaScript interface name that your Android native code will implement.
        // You need to inject a native object into this name using addJavascriptInterface in your Android WebView settings.
        // This name should match the name used in your Kotlin code's addJavascriptInterface.
        const ANDROID_BACKUP_INTERFACE_NAME = "AndroidInterfaceName"; // Modify to match your Kotlin code's name


        /**
         * Handle export data button click event.
         */
        function handleExportData() {
            console.log("Export data button clicked.");
            // Clear previous backup messages
            if (backupMessage) backupMessage.style.display = 'none';
            if (backupError) backupError.style.display = 'none';

            // Get all journal entries data
            const allEntries = loadEntries();
            const jsonData = JSON.stringify(allEntries);

            // Call native interface to export data
            if (window[ANDROID_BACKUP_INTERFACE_NAME] && window[ANDROID_BACKUP_INTERFACE_NAME].exportJournalData) {
                console.log("Calling native exportJournalData...");
                // Call the native method, passing the JSON string as a parameter
                window[ANDROID_BACKUP_INTERFACE_NAME].exportJournalData(jsonData);
                 // The result of the native method execution will be returned via a callback function or message (exportResult)
            } else {
                console.error("Android backup interface or exportJournalData method not available.");
                showTemporaryMessage(backupError, "导出功能不可用，请在支持的环境中运行。", 5000, true);
            }
        }

        /**
         * Handle import data button click event.
         */
        function handleImportData() {
            console.log("Import data button clicked.");
             // Clear previous backup messages
            if (backupMessage) backupMessage.style.display = 'none';
            if (backupError) backupError.style.display = 'none';

            // Call native interface to request import data
            if (window[ANDROID_BACKUP_INTERFACE_NAME] && window[ANDROID_BACKUP_INTERFACE_NAME].requestImportData) {
                console.log("Calling native requestImportData...");
                // Call the native method to request the native code to select a file and read data
                window[ANDROID_BACKUP_INTERFACE_NAME].requestImportData();
                 // After the native method reads the data, it will be passed back via the receiveImportedData callback function
            } else {
                 console.error("Android backup interface or requestImportData method not available.");
                 showTemporaryMessage(backupError, "导入功能不可用，请在支持的环境中运行。", 5000, true);
            }
        }

        /**
         * Called by Android native code to receive imported data.
         * This function needs to be called by the native code using webView.evaluateJavascript().
         * @param {string} jsonData - The JSON string data read from the file.
         */
        window.receiveImportedData = function(jsonData) {
            console.log("receiveImportedData called from native."); // Log receive call
            console.log("Received jsonData:", jsonData ? jsonData.substring(0, 200) + '...' : 'null'); // Log received data (first 200 chars)

            // Clear previous backup messages
            if (backupMessage) backupMessage.style.display = 'none';
            if (backupError) backupError.style.display = 'none';


            if (jsonData) {
                try {
                    const importedEntries = JSON.parse(jsonData);
                    console.log("Parsed imported data:", importedEntries); // Log parsed data
                    console.log("Parsed imported data length:", importedEntries.length); // Log parsed data length

                    // 1. Load existing data
                    let existingEntries = loadEntries();
                    console.log("Existing entries length before merge:", existingEntries.length); // Log existing length

                    // 2. Filter out exact duplicate entries (same date, prices, and notes)
                    const newEntriesToAdd = [];
                    let duplicateCount = 0;

                    importedEntries.forEach(importedEntry => {
                        let isDuplicate = false;
                        // Check if the imported entry is an exact duplicate of any existing entry (date, open, close, high, low, notes)
                        for (let i = 0; i < existingEntries.length; i++) {
                            const existingEntry = existingEntries[i];
                            // Check for exact match (date, open, close, high, low, notes)
                            if (importedEntry.date === existingEntry.date &&
                                importedEntry.open === existingEntry.open &&
                                importedEntry.close === existingEntry.close &&
                                importedEntry.high === existingEntry.high &&
                                importedEntry.low === existingEntry.low &&
                                importedEntry.notes === existingEntry.notes) // Check notes content
                            {
                                isDuplicate = true;
                                duplicateCount++;
                                console.log(`Skipping duplicate entry with date: ${importedEntry.date}`); // Log skipped duplicate
                                break; // Found a duplicate, break the inner loop
                            }
                        }

                        // If it's not a duplicate, add it to the list of new entries to add
                        if (!isDuplicate) {
                            // New imported entries are not pinned by default
                            importedEntry.isPinned = false; // Ensure new entries are not pinned
                            newEntriesToAdd.push(importedEntry);
                        }
                    });

                    console.log(`Found ${duplicateCount} duplicate entries during import.`); // Log duplicate count during import
                    console.log(`Adding ${newEntriesToAdd.length} new unique entries during import.`); // Log new unique entries count during import


                    // 3. Merge existing entries and the new unique entries
                    const mergedEntries = existingEntries.concat(newEntriesToAdd);
                    console.log("Merged entries length:", mergedEntries.length); // Log merged length


                    // 4. Save the merged data to localStorage
                    saveEntries(mergedEntries); // saveEntries now handles sorting by pinned status
                    console.log("Merged data imported and saved successfully."); // Log save success

                    // Display success message, including the count of added and skipped entries
                    showTemporaryMessage(backupMessage, `数据导入完成！新增 ${newEntriesToAdd.length} 条记录，跳过 ${duplicateCount} 条重复记录。`, 5000); // Display for 5 seconds


                    // *** Automatically navigate to the stats list page and refresh the display after successful import ***
                    // Add a small delay to let the user see the success message before navigating
                    setTimeout(() => {
                        console.log("Navigating to statsListPage after import."); // Log navigation
                        showPage('statsListPage');
                    }, 1500); // Navigate after 1.5 seconds


                } catch (e) {
                    console.error("Error parsing imported data:", e); // Log parse error
                    showTemporaryMessage(backupError, "导入失败：数据解析错误。", 5000, true);
                }
            } else {
                console.warn("No data received from native for import."); // Log no data
                showTemporaryMessage(backupError, "导入失败：未选择文件或文件内容为空。", 5000, true);
            }
        };

        /**
         * Called by Android native code to notify the export result.
         * @param {boolean} success - Whether the export was successful.
         * @param {string} [message] - The export result message (optional).
         */
        window.exportResult = function(success, message) {
             console.log("exportResult called from native. Success:", success, "Message:", message); // Log export result
             // Clear previous backup messages
            if (backupMessage) backupMessage.style.display = 'none';
            if (backupError) backupError.style.display = 'none';

             if (success) {
                 showTemporaryMessage(backupMessage, message || "数据导出成功！", 5000);
             } else {
                 showTemporaryMessage(backupError, message || "数据导出失败！", 5000, true);
             }
        };


        // --- Listen for browser history state changes to implement back button functionality ---
        window.onpopstate = function(event) {
            console.log("onpopstate triggered. State:", event.state); // Log popstate event
            // Triggered when the history state changes (e.g., user presses the phone's back button)
            if (event.state && event.state.pageId) {
                // If there is a pageId in the history state, show the corresponding page
                // Note: Set pushState to false when calling showPage here to avoid pushing to history again
                showPage(event.state.pageId, false);
            } else {
                // If the history state is empty (e.g., going back before the initial state of the app), show the homepage
                showPage('homepage', false);
            }
        };


        // --- Initial Load ---
        // When the page loads, show the homepage and set the initial history state.
        document.addEventListener('DOMContentLoaded', () => {
            console.log("DOMContentLoaded fired. Initializing..."); // Log DOMContentLoaded
            showPage('homepage', false); // Do not push to history on initial load
            // Set the history state for the initial page so that subsequent back actions work correctly
            history.replaceState({ pageId: 'homepage' }, '', '#homepage');
            console.log("Initial state replaced with:", { pageId: 'homepage' }); // Log initial state
            // Set initial active filter button
            setActiveFilterButton(currentFilter);
        });

    </script>
</body>
</html>